﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Dominio{
    public class Conta{
        public virtual long Id { get; set; }
        public virtual string Nome { get; set; }
        private IList<Lancamento> _Lancamentos = new List<Lancamento>();
        private IList<Contrato> _Contratos = new List<Contrato>();
        //private IList<PontoDeSaldo> _PontosDeSaldo = new List<PontoDeSaldo>();
        public virtual Usuario Usuario { get; protected set; }
        public virtual decimal Saldo { get; protected set; }

        protected Conta() { }
        public Conta(decimal saldoInicial, string nome, Usuario usuario) {
            this.Usuario = usuario;
            this.Nome = nome;
            this.Saldo = saldoInicial;
            
            //_PontosDeSaldo.Add(new PontoDeSaldo(DateTime.Now, saldoInicial));
        }

        public virtual Lancamento Saca(decimal valor, CategoriaBase categoria) {
            var contrato = new Contrato(valor, 1, DateTime.Now, DateTime.Now, TipoContrato.UNICO, this);
            //_Contratos.Add(contrato);

            return Saca(valor, DateTime.Now, categoria, contrato, TipoLancamento.CONSOLIDADO);
        }

        public virtual Lancamento Saca(decimal valor, DateTime data, CategoriaBase categoria, Contrato contrato, TipoLancamento tipo) {

            valor = (valor > 0) ? (valor * (-1)) : valor;

            var lancamento = new Lancamento(valor, data, tipo, contrato, categoria, this);
            _Lancamentos.Add(lancamento);
            AtualizaSaldo(lancamento);

            return lancamento;
        }

        /*
        public IList<Lancamento> ObtemAgendamentos(int dias) {
            var dataAtual = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day);

            return _Lancamentos
                        .Where(x => x.Tipo == TipoLancamento.ABERTO)
                        .Where(x => x.Data >= dataAtual)
                        .Where(x => x.Data <= dataAtual.AddDays(dias))
                        .ToList();
        }
        
        public IList<Lancamento> ObtemAgendamentos() {
            var dataAtual = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day);

            return _Lancamentos
                        .Where(x => x.Tipo == TipoLancamento.ABERTO)
                        .Where(x => x.Data >= dataAtual)
                        .ToList();
        }
         */

        public virtual Lancamento Deposita(decimal valor, CategoriaBase categoria) {
            var contrato = new Contrato(valor, 1, DateTime.Now, DateTime.Now, TipoContrato.UNICO, this);
            //_Contratos.Add(contrato);

            return Deposita(valor, DateTime.Now, categoria, contrato, TipoLancamento.CONSOLIDADO);
        }

        public virtual void AgendaDeposito(decimal valor, DateTime inicio, int repeticoes, CategoriaBase categoria, TipoContrato tipoContrato) {
            inicio = new DateTime(inicio.Year, inicio.Month, inicio.Day);
            var final = CalculaFinalAgendamento(inicio, repeticoes, tipoContrato);
            var contrato = new Contrato(valor, repeticoes, inicio, final, TipoContrato.UNICO, this);

            for (int i = 1; i <= repeticoes; i++) {
                Deposita(valor, inicio, categoria, contrato, TipoLancamento.ABERTO);
                inicio = ProximaData(tipoContrato, inicio);
            }
        }

        private DateTime CalculaFinalAgendamento(DateTime inicio, int repeticoes, TipoContrato tipoContrato){
            for (int i = 1; i < repeticoes; i++) {
                inicio = ProximaData(tipoContrato, inicio);
            }

            return inicio;
        }

        private DateTime ProximaData(TipoContrato tipo, DateTime data) {
            switch (tipo) { 
                case TipoContrato.MENSAL: return data.AddMonths(1);
                case TipoContrato.ANUAL: return data.AddYears(1);
                case TipoContrato.DIARIO: return data.AddDays(1);
                case TipoContrato.SEMESTRAL: return data.AddMonths(6);
                default: return data.AddMonths(1);
            }
        }

        public virtual Lancamento Deposita(decimal valor, DateTime data, CategoriaBase categoria, Contrato contrato, TipoLancamento tipo) {

            valor = (valor < 0) ? (valor * (-1)) : valor;
            
            var lancamento = new Lancamento(valor, data, tipo, contrato, categoria, this);
            _Lancamentos.Add(lancamento);
            AtualizaSaldo(lancamento);

            return lancamento;
        }

        private void AtualizaSaldo(Lancamento lancamento) {
            if (lancamento.Tipo == TipoLancamento.CONSOLIDADO)
                Saldo = Saldo + lancamento.Valor;
        }

        /*
        public decimal ObtemSaldo() {
            var pontoSaldo = _PontosDeSaldo.LastOrDefault();

            return _Lancamentos
                        .Where(x => x.Data >= pontoSaldo.Data)
                        .Where(x => x.Tipo == TipoLancamento.CONSOLIDADO)
                        .Sum(x => x.Valor) + pontoSaldo.Saldo;
        }*/
    }
}
